package net.entelijan.cobean.examples.util;

import java.awt.BorderLayout;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.Toolkit;
import java.awt.Window;
import java.io.File;
import java.io.FileFilter;
import java.net.URL;
import java.nio.charset.Charset;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.EventObject;
import java.util.List;
import java.util.Random;
import java.util.SortedMap;

import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;

import net.entelijan.cobean.data.literature.ILitService;
import net.entelijan.cobean.data.literature.LitAuthor;
import net.entelijan.cobean.data.literature.LitBook;
import net.entelijan.cobean.data.literature.inmem.InMemLitService;
import net.entelijan.cobean.examples.lit.MainFrame;
import net.entelijan.cobean.util.RandomNameFactory;
import net.miginfocom.swing.MigLayout;

import org.apache.commons.lang.StringUtils;

public abstract class ExamplesUtil {

	private static Random ran = new Random();

	private ExamplesUtil() {
		super();
	}

	public static String listToString(List<?> list, int maxLen) {
		StringBuilder re = new StringBuilder();
		if (list == null) {
			re.append("[null]");
		} else if (list.isEmpty()) {
			re.append("[empty]");
		} else {
			int cnt = 0;
			for (Object obj : list) {
				if (cnt++ > 0) {
					re.append("\n");
				}
				re.append(StringUtils.abbreviate("" + obj, maxLen));
			}
		}
		return re.toString();
	}

	public static List<NestedBean> createNestedBeans(int size) {
		RandomNameFactory namFac = new RandomNameFactory();
		ArrayList<NestedBean> re = new ArrayList<NestedBean>();
		for (int i = 0; i < size; i++) {
			re.add(new NestedBean(i, namFac.nextWord(), null, null));
		}
		return re;
	}

	public static List<NestedBean> createNestedBeansLocales() {
		ran.setSeed(12345L);
		final List<Locale> locales = createLocales();
		ArrayList<NestedBean> re = new ArrayList<NestedBean>();
		int i = 0;
		for (Locale l : locales) {
			final Date dateVal = new Date(
					(long) ran.nextInt(Integer.MAX_VALUE) + 1249646009559L);
			re.add(new NestedBean(i++, l.getDisplayCountry() + "-"
					+ l.getDisplayLanguage(), dateVal, null));
		}
		return re;
	}

	public static List<Locale> createLocales() {
		ArrayList<Locale> re = new ArrayList<Locale>();
		java.util.Locale[] availableLocales = java.util.Locale
				.getAvailableLocales();
		for (java.util.Locale l : availableLocales) {
			if (!l.getCountry().isEmpty()) {
				re.add(new Locale(l));
			}
		}
		return re;
	}

	public static List<Locale> createLocales(String lang) {
		ArrayList<Locale> re = new ArrayList<Locale>();
		for (Locale l : createLocales()) {
			if (l.getLanguage().equals(lang)) {
				re.add(l);
			}
		}
		return re;
	}

	public static List<Charset> createCharsets() {
		ArrayList<Charset> re = new ArrayList<Charset>();
		final SortedMap<String, Charset> availableCharsets = Charset
				.availableCharsets();
		for (Charset cs : availableCharsets.values()) {
			re.add(cs);
		}
		return re;
	}

	public static void openInFrame(JPanel panel) {
		JFrame f = new JFrame();
		f.setSize(300, 400);
		f.setLayout(new BorderLayout());
		f.add(panel, BorderLayout.CENTER);
		f.setVisible(true);
	}

	public static JButton createIconButton(String iconName) {
		JButton re = new JButton();
		URL iconUrl = ExamplesUtil.class.getClassLoader().getResource(iconName);
		if (iconUrl == null) {
			throw new IllegalStateException("Could not find image resource '"
					+ iconName + "' for icon");
		}
		ImageIcon icon = new ImageIcon(iconUrl);
		re.setIcon(icon);
		return re;
	}

	public static JLabel createIconLabel(String iconName) {
		JLabel re = new JLabel();
		URL iconUrl = ExamplesUtil.class.getClassLoader().getResource(iconName);
		if (iconUrl == null) {
			throw new IllegalStateException("Could not find image resource '"
					+ iconName + "' for icon");
		}
		ImageIcon icon = new ImageIcon(iconUrl);
		re.setIcon(icon);
		return re;
	}

	public static Component createButtonsPanel(int buttonWidth,
			JButton... buttons) {
		JPanel re = new JPanel();
		re.setLayout(new MigLayout("insets 0 0 0 0"));
		int cnt = 0;
		for (JButton b : buttons) {
			re.add(b, "w 20:" + buttonWidth + ":" + buttonWidth);
			cnt++;
		}
		return re;
	}

	public static Date createDate(String pattern, String value) {
		try {
			SimpleDateFormat sdf = new SimpleDateFormat(pattern);
			return sdf.parse(value);
		} catch (ParseException e) {
			throw new IllegalArgumentException("Cannot create a date for '"
					+ value + "' using '" + pattern + "'. " + e.getMessage());
		}
	}

	/**
	 * Selects a random fiel or directory.
	 * 
	 * @param rootDir
	 *            The root dir from where the files are selected
	 * @param maxDepth
	 *            The number of subdirectories that will be searched.
	 * @return A randomly choosen file from inside the root directory or from
	 *         inside a subdirectory of the root directory.
	 */
	public static File getRandomFile(File rootDir, int maxDepth) {
		File re = null;
		for (int i = 0; i < 20; i++) {
			int actualDepth = ran.nextInt(maxDepth);
			File file = getRandomFile(rootDir, 0, actualDepth);
			if (file != null) {
				re = file;
				break;
			}
		}
		if (re == null) {
			throw new IllegalStateException("Could not find a random file in '"
					+ rootDir + "' with depth " + maxDepth);
		}
		return re;
	}

	private static File getRandomFile(File rootDir, int currentDepth,
			int actualDepth) {
		File re;
		if (currentDepth == actualDepth) {
			File[] files = rootDir.listFiles();
			if (files == null) {
				re = null;
			} else if (files.length > 0) {
				int idx = ran.nextInt(files.length);
				re = files[idx];
			} else {
				re = null;
			}
		} else if (currentDepth < actualDepth) {
			File[] dirs = rootDir.listFiles(new FileFilter() {

				@Override
				public boolean accept(File pathname) {
					return pathname.isDirectory();
				}

			});
			if (dirs.length <= 0) {
				re = null;
			} else {
				int idx = ran.nextInt(dirs.length);
				re = getRandomFile(dirs[idx], currentDepth + 1, actualDepth);
			}
		} else {
			throw new IllegalStateException(
					"'currentDepth' must never be greater than 'actualDepth'. "
							+ currentDepth + " > " + actualDepth);
		}
		return re;
	}

	public static ILitService createTestService() {
		InMemLitService re = new InMemLitService();
		re.setResource("lit01.xml");
		return re;
	}

	public static List<LitBook> filterBooksByYear(List<LitBook> allBooks,
			int fromYear, int toYear) {
		List<LitBook> re = new ArrayList<LitBook>();
		for (LitBook b : allBooks) {
			if (b.getYear() >= fromYear && b.getYear() <= toYear) {
				re.add(b);
			}
		}
		return re;
	}

	public static List<LitAuthor> filterAuthorsWithBooks(
			List<LitAuthor> allAuthors) {
		ArrayList<LitAuthor> re = new ArrayList<LitAuthor>();
		for (LitAuthor a : allAuthors) {
			if (a.getBooks() != null && a.getBooks().size() > 0) {
				re.add(a);
			}
		}
		return re;
	}

	public static List<LitAuthor> loadAllAuthorsWithBooks(ILitService service,
			List<LitAuthor> loadAllAuthors) {
		List<LitAuthor> re = new ArrayList<LitAuthor>();
		for (LitAuthor a : loadAllAuthors) {
			re.add(service.loadAuthor(a.getId()));
		}
		return re;
	}

	public static void centerFrame(MainFrame frame) {
		Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
		int x = (screenSize.width - frame.getWidth()) / 2;
		int y = (screenSize.height - frame.getHeight()) / 2;
		frame.setLocation(x, y);
	}

	public static void disposeRoot(EventObject event) {
		Window root = (Window) SwingUtilities
				.getRoot((Component) event.getSource());
		root.dispose();
	}

}
